﻿#region

using System;
using System.Collections.Generic;
using System.ComponentModel;
using EditeurSyntaxiqueVocal.Configuration;
using EditeurSyntaxiqueVocal.Forms;
using EditeurSyntaxiqueVocal.Forms.CommunicationsForm;
using SpeechLib;
using TextEditor;
using TextEditor.Actions;
using TextEditor.Document;

#endregion

namespace EditeurSyntaxiqueVocal.Controls
{
    /// <summary>
    /// Class EditeurText. hériter de TextEditorControl.
    /// </summary>
    [ToolboxItem(true)]
    public partial class EditeurText : TextEditorControl
    {
        /// <summary>
        /// 
        /// </summary>
        private bool _ActiveMajuscule;
        private bool _normal = true;

        //si la document est protéger la l'excution de l'evenement DocumentChanged ou DocumentAboutToBeChanged.
        private bool _ValideDocumentChanged;
        private string stringAvantInsertion;

        public bool normal
        {
            get { return _normal; }
            set { _normal = value; }
        }

        public new IDocument Document
        {
            get {
                return ActiveTextAreaControl.TextArea.Document;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private string[] TabMot;

        /// <summary>
        /// Constructeur.
        /// </summary>
        public EditeurText()
        {
            InitializeComponent();
            UseAntiAliasFont = true;
            _ValideDocumentChanged = true;
            IsIconBarVisible = false;
            if (_normal)
            {
                #region MyRegion

                //ShowEOLMarkers = false;

                //ShowInvalidLines = false;

                //ShowSpaces = false;

                //ShowTabs = true;

                ShowMatchingBracket = true;

                switch (BracketMatchingStyle.ToString().ToLower())
                {
                    case "before":
                        BracketMatchingStyle =
                            BracketMatchingStyle.Before;
                        break;
                    case "after":
                        BracketMatchingStyle =
                            BracketMatchingStyle.After;
                        break;
                }

                ShowLineNumbers = true;

                ShowHRuler = false;

                ShowVRuler = true;

                // EnableFolding = false;

                ConvertTabsToSpaces = false;

                TabIndent = 4;

                VRulerRow = 80;

                AllowCaretBeyondEOL = false;

                TextEditorProperties.AutoInsertCurlyBracket = false;

                UseAntiAliasFont = true;
                

                switch (IndentStyle.ToString().ToLower())
                {
                    case "auto":
                        IndentStyle = IndentStyle.Auto;
                        break;
                    case "none":
                        IndentStyle = IndentStyle.None;
                        break;
                    case "smart":
                        IndentStyle = IndentStyle.Smart;
                        break;
                }

                #endregion 
            }
            ContextMenuStrip = contextMenuStrip;
        }

        /// <summary>
        /// Activé ou désactivé le rendeur de muniscule à majuscule.
        /// </summary>
        public bool ActiveMajuscule
        {
            get { return _ActiveMajuscule; }
            set
            {
                //on charge la table TabMot à partir de WordsZ.txt
                ChargerTabMot();
                if (_ActiveMajuscule != value)
                    //si vraie on ajoute les deux evenements.
                    if (value)
                    {
                        ActiveTextAreaControl.TextArea.Document.DocumentChanged += Document_DocumentChanged;
                        ActiveTextAreaControl.TextArea.Document.DocumentAboutToBeChanged +=
                            Document_DocumentAboutToBeChanged;
                    }
                    else //si fausse on suprime les deux evenements.
                    {
                        ActiveTextAreaControl.TextArea.Document.DocumentChanged -= Document_DocumentChanged;
                        ActiveTextAreaControl.TextArea.Document.DocumentAboutToBeChanged -=
                            Document_DocumentAboutToBeChanged;
                    }
                _ActiveMajuscule = value;
            }
        }

        /// <summary>
        /// Si no insere un text, Alors rendere leurs mots clé de Z en majuscule.
        /// </summary>
        private void Document_DocumentAboutToBeChanged(object sender, DocumentEventArgs e)
        {
            //si la document est protéger la l'excution de l'evenement DocumentChanged ou DocumentAboutToBeChanged,Alors return.
            if (!_ValideDocumentChanged) return;
            //si le text de l'evenement est null ou vide, Alors return.
            if (string.IsNullOrEmpty(e.Text)) return;
            //si la lengeur de text de l'evenement est égal à un, Alors c'est une insrtion de un caractère.
            if (e.Text.Length == 1) return;

            stringAvantInsertion = e.Text;
            int start = 0;
            //on décompose le text inserer sur les caractère suivants:
            string[] TabStr = stringAvantInsertion.Split(new char[]
                                                             {
                                                                 '~', '!', '%', '^', '*', '(', ')', '-',
                                                                 '+', '=', '|', '\\', '#', '/', '{', '}',
                                                                 '[', ']', ':', ';', '<', '>', ',', '.',
                                                                 '?', ' '
                                                             }, StringSplitOptions.RemoveEmptyEntries);
            //Arête l'execution de cette evenement.
            _ValideDocumentChanged = false;
            foreach (string ss in TabStr)
                foreach (string s in TabMot)
                    //si un mot dans la text inserer dans la table TabMot, Alors remplacer par la mot en majuscule.
                    if (ss.ToLower() == s.ToLower())
                    {
                        //détermine l'indexe de ss à partir de start.
                        start = stringAvantInsertion.IndexOf(ss, start);
                        //remplace ss par sa majuscule.
                        stringAvantInsertion =
                            //avnat le start
                            stringAvantInsertion.Substring(0, start)
                            //vers sa majuscule.
                            + ss.ToUpper()
                            //aprés le start + ss.Length
                            + stringAvantInsertion.Substring(start + ss.Length,
                                                             stringAvantInsertion.Length
                                                             - start - ss.Length);
                        //on déplace.
                        start += ss.Length;
                        break;
                    }
            //Réprise l'execution de cette evenement.
            _ValideDocumentChanged = true;
        }

        /// <summary>
        /// Pour rendera en majuscule les mots clé de language Z(par exemple : if ==> IF, end==>END)..
        /// Les mots clé qui va être rendera en majuscule exist dans le fichier (.\Configuration\WordsZ.txt)
        /// </summary>
        private void Document_DocumentChanged(object sender, DocumentEventArgs e)
        {
            //si le document est protéger l'excution de l'evenement DocumentChanged ou DocumentAboutToBeChanged, Alors return.
            if (!_ValideDocumentChanged) return;
            //si le text de l'evenement est null ou vide, Alors return.
            if (!_ActiveMajuscule) return;
            int i = 0;
            if (string.IsNullOrEmpty(e.Text))
                i = 1;
            else if (e.Text.Length == 1)
            {
                if (TextUtilities.IsLetterDigitOrUnderscore(e.Text[0]))
                    return;
            }
            else // c'esta  à dir un insertion:
            {
                //Arête l'execution de cette evenement.
                _ValideDocumentChanged = false;
                //pemplace le text inserer par sa majuscule (par stringAvantInsertion).
                ActiveTextAreaControl.TextArea.Document.Remove(e.Offset, e.Text.Length);
                ActiveTextAreaControl.TextArea.Document.Insert(e.Offset, stringAvantInsertion);
                //Réprise l'execution de cette evenement.
                _ValideDocumentChanged = true;
                return;
            }
            //Arête l'execution de cette evenement.
            _ValideDocumentChanged = false;
            int start, end;
            //returne le mot sur position du Caret.
            string str = TextUtilities.GetWordAt(e.Document, e.Offset - 1, out start, out end);
            if (!string.IsNullOrEmpty(str) && !IsMajuscule(str))
                foreach (string s in TabMot)
                    if (str.ToLower() == s.ToLower())
                    {
                        ActiveTextAreaControl.Document.Remove(start, end - start + 1 + 1 - i);
                        ActiveTextAreaControl.TextArea.Document.Insert(start, str.ToUpper() + e.Text);
                        ActiveTextAreaControl.TextArea.Document.UndoStack.Pop();
                        ActiveTextAreaControl.TextArea.Document.UndoStack.Pop();
                        break;
                    }
            //Réprise l'execution de cette evenement.
            _ValideDocumentChanged = true;
        }

        ///<summary>
        /// Charge la table TabMot à partir de XMLMotCleZFrEun.
        /// (WordsZ.txt, et décomposer sur {"\r\n", "\n", " "}.)
        ///</summary>
        public void ChargerTabMot()
        {
            try
            {
                //using (StreamReader streamReader = new StreamReader(VarStatic.NomCurrantFile))
                //    TabMot = streamReader.ReadToEnd().Split(new string[] {"\r\n", "\n", " "},
                //                                            StringSplitOptions.RemoveEmptyEntries);

                ListeMotsCleZ listeMotsCleZ = new ListeMotsCleZ();
                List<string[]> parser = listeMotsCleZ.ParserXml();
                TabMot = new string[parser.Count];
                for (int i = 0; i < parser.Count; i++)
                    TabMot[i] = parser[i][2];
            }
            catch (Exception)
            {
            }
        }

        ///<summary>
        /// Executer une action sur cette editeur, peut être Cut, Paste, Copy,... .
        ///</summary>
        ///<param name="action">L'action qui va être executer.</param>
        public void ExecuteAction(IEditAction action)
        {
            if (action == null) return;

            TextAreaControl control = ActiveTextAreaControl;
            if (control == null) return;

            TextArea area = control.TextArea;
            if (area == null) return;

            area.AutoClearSelection = true;
            {
                BeginUpdate();
                try
                {
                    lock (Document)
                    {
                        action.Execute(area);
                        if (area.SelectionManager.HasSomethingSelected
                            && area.AutoClearSelection /*&& caretchanged*/)
                            if (area.Document.TextEditorProperties.DocumentSelectionMode
                                == DocumentSelectionMode.Normal)
                                area.SelectionManager.ClearSelection();
                    }
                }
                finally
                {
                    EndUpdate();
                    area.Caret.UpdateCaretPosition();
                }
            }
        }

        /// <summary>
        /// Inseret une text dans la posistion de Caret(Cursor) actualle.
        /// </summary>
        /// <param name="text">Le text a inserer</param>
        public void EditInsert(string text)
        {
            if (String.IsNullOrEmpty(text)) return;

            TextAreaControl control = ActiveTextAreaControl;
            if (control == null) return;

            TextArea area = control.TextArea;
            if (area == null) return;
            //string[] lines = text.Split(new string[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            //foreach (string line in lines)
            {
                area.InsertString(text);
                //new End().Execute(area);
                //Forms.CommunicationsForm.VoixMainForm.GenererListPosition(area.Caret.Offset, line, false);                
                //new Return().Execute(area);
            }
            if (InsertText != null)
                InsertText(null, null);
        }

        public event EventHandler InsertText = null;

        /// <summary>
        /// Inseret une text dans la posistion de Caret(Cursor) actualle.
        /// </summary>
        /// <param name="text">Le text a inseret</param>
        /// <param name="OffsetCursorMoins">Le nombre de caractère a pouvoire de Caret.</param>
        public void EditInsert(string text, int OffsetCursorMoins)
        {
            if (String.IsNullOrEmpty(text)) return;

            TextAreaControl control = ActiveTextAreaControl;
            if (control == null) return;

            TextArea area = control.TextArea;
            if (area == null) return;

            area.InsertString(text);

            //bool hasSelection = area.SelectionManager.HasSomethingSelected;

            //if (!hasSelection)
            //{
            //    int offset = control.Caret.D1;
            //    offset -= OffsetCursorMoins;
            //    area.Caret.Position = area.Document.OffsetToPosition(offset);
            //}
        }

        /// <summary>
        /// Détérminer si cette mot(str) est contient des caractères est majuscule donc 
        /// return true, sinon return false.
        /// </summary>
        private static bool IsMajuscule(IEnumerable<char> str)
        {
            foreach (char c in str)
                if (c == '_') continue;
                else if (c < 'A'
                         || c > 'Z')
                    return false;
            return true;
        }

        private void hhToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Cut().Execute(ActiveTextAreaControl.TextArea);

        }

        private void klToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Paste().Execute(ActiveTextAreaControl.TextArea);
        }

        private void bnToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Copy().Execute(ActiveTextAreaControl.TextArea);
        }

        private void speakToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                VoixMainForm.MotCleObjRecoContext.Voice.Speak(
                    MainForm.OngletActive.EditeurTextOnglet.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText,
                    SpeechVoiceSpeakFlags.SVSFlagsAsync);
            }
            catch (Exception error)
            {
            }
        }

       
    }
}